# -*- coding: utf-8 -*-

import os
from utils.version import VERSION


def create_simcxx_pro(project_name: str,
                      simcxx_path: str,
                      juna_path: str):
    pro_path = os.path.join(simcxx_path, '{}.pro'.format(project_name))
    # Convert all the windows '\\' to '//'
    juna_path = juna_path.replace('\\', '/')
    # Construct the file content.
    pro_text = ['# C++ simulation project file.\n',
                '# Project: {}'.format(project_name),
                '# Created by Hardware Architecture Render Engine (HARE)',
                '# Version: {}\n'.format(VERSION),
                '# Set the library template',
                'TEMPLATE = lib\n',
                '# Create the target as a library',
                'TARGET = $$qtLibraryTarget({})\n'.format(project_name),
                '# Enable plugin and C++ 17 support',
                'CONFIG += plugin c++17\n',
                '# Libraries',
                'INCLUDEPATH += \\',
                '    {} \\'.format(juna_path),
                '    ip',
                '    uut\n',
                '# Header and Cpp files',
                'SOURCES += \\',
                '    uut/{}_top.cpp \\'.format(project_name),
                '    {}_entry.cpp\n'.format(project_name),
                'HEADERS += \\',
                '    uut/{}_top.h \\'.format(project_name),
                '    {}_entry.h\n'.format(project_name)
                ]
    # Write the content to project file.
    with open(pro_path, 'w') as project_file:
        project_file.write('\n'.join(pro_text))


def create_simcxx_entry_header(project_name: str, simcxx_path: str):
    header_flag = project_name.upper() + '_ENTRY_H'
    # Construct the file content.
    h_text = ['#ifndef {}'.format(header_flag),
              '#define {}\n'.format(header_flag),
              '/*',
              ' * Plugin entry header file of {}.'.format(project_name),
              ' * Created by Hardware Architecture Render Engine (HARE)',
              ' * Version: {}'.format(VERSION),
              ' *',
              ' * This is the entry point of the plugin. ',
              ' * Usually it should not need to be modified.',
              ' */\n',
              '#include <QObject>',
              '#include <QtPlugin>\n',
              '#include "interface.h"\n',
              'class HareruPlugin : public QObject, JunaInterface',
              '{',
              '    Q_OBJECT',
              '    Q_PLUGIN_METADATA(IID "hareru.juna.JunaInterface")',
              '    Q_INTERFACES(JunaInterface)\n',
              'public:',
              '    TopModule *top_module() override;',
              '};\n',
              '#endif // {}\n'.format(header_flag)]
    # Write the content to header file.
    header_name = '{}_entry.h'.format(project_name)
    with open(os.path.join(simcxx_path, header_name), 'w') as header_file:
        header_file.write('\n'.join(h_text))


def create_simcxx_entry_cpp(project_name: str, simcxx_path: str):
    # Get the file basename.
    basename = '{}_entry'.format(project_name)
    # Construct the file content.
    cpp_text = ['/*',
                ' * Plugin entry cpp file of {}.'.format(project_name),
                ' * Created by Hardware Architecture Render Engine (HARE)',
                ' * Version: {}'.format(VERSION),
                ' *',
                ' * This is the entry point of the plugin. ',
                ' * Usually it should not need to be modified.',
                ' */\n',
                '#include "uut/{}_top.h"'.format(project_name),
                '#include "{}.h"\n'.format(basename),
                'TopModule *HareruPlugin::top_module()',
                '{',
                '    return new DesignUnitTest();',
                '}\n']
    # Write the content to cpp file.
    cpp_name = '{}.cpp'.format(basename)
    with open(os.path.join(simcxx_path, cpp_name), 'w') as cpp_file:
        cpp_file.write('\n'.join(cpp_text))


def create_simcxx_top_module(project_name: str, simcxx_path: str):
    header_flag = project_name.upper() + '_TOP_H'
    # Construct the top module header.
    h_text = ['#ifndef {}'.format(header_flag),
              '#define {}\n'.format(header_flag),
              '/*',
              ' * Top module header file of {}.'.format(project_name),
              ' * Created by Hardware Architecture Render Engine (HARE)',
              ' * Version: {}'.format(VERSION),
              ' *',
              ' * This is the top module header file. ',
              ' * Usually it should not need to be modified.',
              ' */\n',
              '#include "node.h"\n',
              'class DesignUnitTest : public TopModule',
              '{',
              'public:',
              '    explicit DesignUnitTest();',
              '};\n',
              '#endif // {}\n'.format(header_flag)]
    uut_path = os.path.join(simcxx_path, 'uut')
    with open(os.path.join(uut_path, '{}_top.h'.format(project_name)), 'w') as uut_header:
        uut_header.write('\n'.join(h_text))
    # Construct the top module cpp.
    cpp_text = ['/*',
                ' * Top module cpp file of {}.'.format(project_name),
                ' * Created by Hardware Architecture Render Engine (HARE)',
                ' * Version: {}'.format(VERSION),
                ' */\n',
                '#include "{}_top.h"\n'.format(project_name),
                'DesignUnitTest::DesignUnitTest() :',
                '    TopModule()',
                '{',
                '    // TODO: Please add your TopModule test code here.',
                '}\n']
    with open(os.path.join(uut_path, '{}_top.cpp'.format(project_name)), 'w') as uut_cpp:
        uut_cpp.write('\n'.join(cpp_text))


def create_simcxx_project(project_path: str, juna_path: str):
    # Convert the path into absolute file.
    project_path = os.path.abspath(project_path)
    juna_path = os.path.abspath(juna_path)
    # Create the simcxx directory.
    simcxx_path = os.path.join(project_path, 'simcxx')
    os.makedirs(simcxx_path, exist_ok=True)
    # Create the ip and uut directory under the folder.
    os.makedirs(os.path.join(simcxx_path, 'ip'), exist_ok=True)
    os.makedirs(os.path.join(simcxx_path, 'uut'), exist_ok=True)
    # Construct the get the project name.
    _, project_name = os.path.split(project_path)
    project_name = project_name.lower()
    # Now create the Qt-project file.
    create_simcxx_pro(project_name, simcxx_path, juna_path)
    # Construct the entry module.
    create_simcxx_entry_header(project_name, simcxx_path)
    create_simcxx_entry_cpp(project_name, simcxx_path)
    # Construct the top module.
    create_simcxx_top_module(project_name, simcxx_path)
